package se.vgregion.excel.tools;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Writes zip 'material' from one source to another. Does not do anything special with the content. Purpose with
 * this class is to extend it to do something more useful. Override the visit method to manipulate the incoming
 * data before sending it on to the super.visit method.
 * 
 * @author claes.lundahl
 */
public class ZipToZipWriter extends ZipEntryVisitor {

    private ZipOutputStream zos;

    private List<ZipEntry> entriesPassed = new ArrayList<ZipEntry>();

    /**
     * Starts the transfer from one stream to the other.
     * 
     * @param in
     *            the content to be copied.
     * @param os
     *            the target of the operation.
     */
    public void process(InputStream in, OutputStream os) {
        zos = new ZipOutputStream(os);
        process(in);
        try {
            zos.flush();
            zos.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            zos = null;
        }
    }

    /**
     * Writes chunks of bytes from the source to the target stream.
     * 
     * @param entry
     *            current entr to process.
     * @param bytesIn
     *            count of the chunk that is processed.
     * @param readBuffer
     *            the buffer that carries the chunk of bytes this iteration.
     */
    @Override
    protected void visit(ZipEntry entry, int bytesIn, byte[] readBuffer) {

        if (zos == null) {
            throw new RuntimeException("Dont use the " + this.getClass().getSimpleName()
                    + ".process(InputStream in), use the " + this.getClass().getSimpleName()
                    + ".process(InputStream in, OutputStream os) with a non-null value for parameter 'os'.");
        }

        try {
            if (!entriesPassed.contains(entry)) {
                ZipEntry nextEntry = new ZipEntry(entry.getName());
                entriesPassed.add(entry);
                zos.putNextEntry(nextEntry);
            }
            zos.write(readBuffer, 0, bytesIn);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
